// -*- C++ -*-

//========================================================================
/**
 * Author   : cuisw <shaovie@gmail.com>
 * Date     : 2009-05-29 02:24
 */
//========================================================================

#ifndef NDK_SELECT_REACTOR_H_
#define NDK_SELECT_REACTOR_H_

#include "ndk/reactor_impl.h"

namespace ndk
{
  /**
   * @class select_event_tuple
   *
   * @brief 
   */
  class select_event_tuple
  {
  public:
    select_event_tuple()
      : handle_(NDK_INVALID_HANDLE),
      event_handler_(0)
    { }

    //
    select_event_tuple(ndk_handle h, event_handler *eh)
      : handle_(h),
      event_handler_(eh)
    { }

    //
    bool operator == (const select_event_tuple &rhs) const
    { return this->handle_ == rhs.handle_; }
    //
    bool operator != (const select_event_tuple &rhs) const
    { return !(*this == rhs); }

  public:
    ndk_handle handle_;
    event_handler *event_handler_;
  };
  /**
   * @class select_reactor_handler_repository
   *
   * @brief 
   */
  class select_reactor_handler_repository
  {
  public:
    int open(size_t max_size);

    int close(void);

    event_handler *find(ndk_handle );

    int bind(ndk_handle, event_handler *, reactor_mask );

    int unbind(ndk_handle, reactor_mask );
    
    int is_invalid_handle(ndk_handle handle) const;

    int handle_in_range(ndk_handle handle) const;
  private:
    // Maximum number of handles.
    int max_size_;

    //
#if defined NDK_LINUX
    select_event_tuple *handlers_;
#elif defined NDK_WIN32
    typedef std::map<ndk_handle, event_handler *> handler_list_t;
    typedef typename handler_list_t::iterator handler_list_iter;
    handler_list_t handlers_;
#endif
  };
  /**
   * @class select_reactor_notify
   *
   * @brief Event handler used for unblocking the select_reactor from its event 
   * loop.
   *
   * This event handler is used internally by the select_reactor as a means to 
   * allow a thread other then the one running the event loop to unblock the 
   * event loop.
   */
  class select_reactor_notify : public reactor_notify
  {
  public:
    select_reactor_notify();
    // = Initialization and termination methods.
    virtual int open(reactor_impl *);

    virtual int close();

    /**
     * Called by a thread when it wants to unblock the <reactor_impl>.
     * This wakeups the <reactor_impl> if currently blocked.  Pass over
     * both the <event_handler> *and* the <mask> to allow the caller to
     * dictate which <event_handler> method the <reactor_impl> will invoke.
     */
    virtual int notify(event_handler *eh = 0,
                       reactor_mask mask = event_handler::except_mask);

    // Returns the ndk_handle of the notify pipe on which the reactor
    // is listening for notifications so that other threads can unblock
    // the <reactor_impl>.
    virtual ndk_handle notify_handle(void);

    // Read one of the notify call on the <handle> into the
    // <buffer>. This could be because of a thread trying to unblock
    // the <reactor_impl>
    virtual int read_notify_pipe(ndk_handle handle,
                                 notification_buffer &buffer);

    // Purge any notifications pending in this reactor for the specified
    // event_handler object. Returns the number of notifications purged. 
    // Returns -1 on error.
    virtual int purge_pending_notifications(event_handler * = 0,
                                            reactor_mask = event_handler::all_events_mask);

    // Handle readable event
    virtual int handle_input(ndk_handle handle);
  protected:
    // Keep a back pointer to the select_reactor. 
    select_reactor *slt_reactor_;

    /**
     * Contains the ndk_handle the select_reactor is listening on, as well as
     * the ndk_handle that threads wanting the attention of the select_reactor 
     * will write to.
     */
    pipe notification_pipe_;
  }; 
  /**
   * @class select_reactor
   *
   * @brief 
   */
  class select_reactor : public reactor_impl
  {
  public:
    select_reactor()
    { }

    ~select_reactor()
    { }
  };
} // namespace ndk

#endif // NDK_SELECT_REACTOR_H_

